package com.learning.optimize.jdk.reflect.jdbc;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * ClassName: JdbcGenericDaoImpl
 * Description: JdbcGenericDaoImpl 基础实现，反射实现
 * Date: 2018/7/18 14:19 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
public class JdbcGenericDaoImpl<T> implements GenericDao<T> {

    private Class<T> clazz;

    public JdbcGenericDaoImpl() {
        // 利用反射得到泛型的真实类型
        Type genType = getClass().getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        clazz = (Class) params[0];
    }

    @Override
    public List<T> getALL() {

        PreparedStatement ps = null;
        ResultSet rs = null;

        List<T> list = Lists.newArrayList();
        Connection connection = JdbcDaoHelper.getConnection();
        // 获取表名
        String tableName = clazz.getSimpleName().toLowerCase();

        // 获取属性，是全包名的
        Field[] fields = clazz.getDeclaredFields();
        // 解析获取属性名
        List<String> collect = Arrays.stream(fields).map(Field::getName).collect(Collectors.toList());
        // 拼接属性sql
        String fieldNames = Joiner.on(",").join(collect);

        String sql = "select " + fieldNames + " from " + tableName;
        //select id,name,pwd from user
        System.out.println(sql);
        try {
            ps = connection.prepareStatement(sql);

            //执行SQL
            rs = ps.executeQuery();
            while (rs.next()) {
                T t = clazz.newInstance();
                initObject(t, fields, rs);
                list.add(t);
            }

            //释放资源
            JdbcDaoHelper.release(ps, rs);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcDaoHelper.release(ps, rs);
        }

        return list;
    }

    /**
     * 映射实体，把查询的数据与实体做映射
     *
     * @param t
     * @param fields
     * @param rs
     * @throws Exception
     */
    private void initObject(T t, Field[] fields, ResultSet rs) throws Exception {
        for (Field field : fields) {
            Object paramVal = null;
            // 属性名
            String propertyName = field.getName();
            // 属性类型
            Class<?> clazzField = field.getType();

            // 判断属性类型
            if (clazzField == String.class) {
                paramVal = rs.getString(propertyName);
            } else if (clazzField == short.class || clazzField == Short.class) {
                paramVal = rs.getShort(propertyName);
            } else if (clazzField == int.class || clazzField == Integer.class) {
                paramVal = rs.getInt(propertyName);
            } else if (clazzField == long.class || clazzField == Long.class) {
                paramVal = rs.getLong(propertyName);
            } else if (clazzField == float.class || clazzField == Float.class) {
                paramVal = rs.getFloat(propertyName);
            } else if (clazzField == double.class || clazzField == Double.class) {
                paramVal = rs.getDouble(propertyName);
            } else if (clazzField == boolean.class || clazzField == Boolean.class) {
                paramVal = rs.getBoolean(propertyName);
            } else if (clazzField == byte.class || clazzField == Byte.class) {
                paramVal = rs.getByte(propertyName);
            } else if (clazzField == char.class || clazzField == Character.class) {
                paramVal = rs.getCharacterStream(propertyName);
            } else if (clazzField == Date.class) {
                paramVal = rs.getTimestamp(propertyName);
            } else if (clazzField.isArray()) {
                //以逗号分隔的字符串
                paramVal = Splitter.on(",").splitToList(rs.getString(propertyName)).toArray();
            }

            // 利用 PropertyDescriptor 获取set、get方法
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, t.getClass());
            //调用set方法。Write为set，read为get
            pd.getWriteMethod().invoke(t, paramVal);
        }
    }

}